package com.scott.framework.servlet;

import com.scott.framework.annotation.Controller;
import com.scott.framework.annotation.RequestMapping;
import com.scott.framework.context.SimpleApplicationContext;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class SimpleDispatcherServlet extends HttpServlet {

    private static final long serialVersionUID = 1699762942660124843L;

    private static final String LOCATION = "contextConfigLocation";

    private Map<String, Handler> handlerMap = new HashMap<String, Handler>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(">>>>>>>>>   调用  <<<<<<<<<<");
        try {
            doDispatch(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
            out(resp,"500 exception ,meg:" + Arrays.toString(e.getStackTrace()));
        }
    }


    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //从HandlerMapping中获取request对应的Handler
        Handler handler = getHandler(req);

        if (handler == null) {
            out(resp,"404 not found");
        }

        //根据handler获取此handler对应的适配器
        HandlerAdapter adapter = getHandlerAdapter(handler);

        //执行适配器方法,调用具体的Controller方法
        adapter.handle(req, resp, handler);
    }

    /**
     * 根据Url对应的handler 查找这个url的handler对应的适配器
     * @param handler url对应的handler
     * @return handler适配器
     */
    private HandlerAdapter getHandlerAdapter(Handler handler) {
        return null;
    }

    private Handler getHandler(HttpServletRequest req) {

        if (handlerMap.isEmpty()) {
            return null;
        }

        String contextPath = req.getContextPath();

        String requestURI = req.getRequestURI();

        String url = requestURI.replace(contextPath, "");
        return handlerMap.get(url);

    }


    /**
     * 容器初始化
     *
     * @throws ServletException 异常
     */
    @Override
    public void init(ServletConfig config) throws ServletException {

        //启动容器
        SimpleApplicationContext context = new SimpleApplicationContext(config.getInitParameter(LOCATION));

        Map<String, Object> ioc = context.getAll();


        //解析请求 暂未实现
        initMultipartResolver(context);

        //多语言 国际化 暂未实现
        initLocaleResolver(context);

        //主题 view 暂未实现
        initThemeResolver(context);

        //url 和 Method映射关系 重要
        initHandlerMappings(context);

        //适配器（匹配url ->controller ->view） 重要
        initHandlerAdapters(context);

        //统一异常处理
        initHandlerExceptionResolvers(context);

        //视图转发（根据视图名称匹配到对应的页面模板）
        initRequestToViewNameTranslator(context);

        //解析模板中的内容，根据服务器返回的数据以及模板生成对应的html代码
        initViewResolvers(context);

        //
        initFlashMapManager(context);

        System.out.println(">>>>>>>>>   servlet init success   <<<<<<<<<<");
    }


    //解析请求
    private void initMultipartResolver(SimpleApplicationContext context) {
    }

    //多语言 国际化
    private void initLocaleResolver(SimpleApplicationContext context) {
    }

    //主题 view
    private void initThemeResolver(SimpleApplicationContext context) {
    }

    //url 和 Method映射关系
    private void initHandlerMappings(SimpleApplicationContext context) {
        //获取IOC容器中的所有类
        Map<String, Object> ioc = context.getAll();

        if (ioc.isEmpty()) {
            return;
        }

        //将所有LcsController 类注解的类里面的方法全部找出来
        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();

            //过滤掉所有非LcsController的bean
            if (!clazz.isAnnotationPresent(Controller.class)) {
                continue;
            }

            String url = "";
            if (clazz.isAnnotationPresent(RequestMapping.class)) {
                RequestMapping classRequestmapping = clazz.getAnnotation(RequestMapping.class);
                url = classRequestmapping.value();
            }

            //获取类的所有方法
            Method[] methods = clazz.getMethods();

            for (Method method : methods) {
                //如果方法上有LcsRequestMapping注解，则获取对应注解的地址，将其和类上的地址进行拼接，并构造对应的Handler
                if (!method.isAnnotationPresent(RequestMapping.class)) {
                    continue;
                }
                RequestMapping methodRequest = method.getAnnotation(RequestMapping.class);

                //需要处理url的异常情况
                String requestUrl = url + methodRequest.value();
                handlerMap.put(requestUrl, new Handler(clazz, method));
            }


        }

        //并将所有RequestMapping注解的方法找出来，映射到外面由别人访问
        //获取所有RequestMapping上的
    }

    //适配器
    private void initHandlerAdapters(SimpleApplicationContext context) {

        if (handlerMap.isEmpty()) {
            return;
        }

        //循环遍历所有的handler
        for (Map.Entry<String, Handler> entry : handlerMap.entrySet()) {
            //获取方法上的所有参数
            Class<?>[] paramsTypes = entry.getValue().method.getParameterTypes();

            //参数是有顺序的，但是通过反射是获取不到参数具体的命名的，因为参数是形参
            for(int i=0;i<paramsTypes.length;i++){
                Class<?> paramsType = paramsTypes[i];

                String paramsNames = paramsType.getName();
            }

        }
    }

    //统一异常处理
    private void initHandlerExceptionResolvers(SimpleApplicationContext context) {
    }

    //视图转发（根据视图名称匹配到对应的页面模板）
    private void initRequestToViewNameTranslator(SimpleApplicationContext context) {
    }

    //解析模板中的内容，根据服务器返回的数据以及模板生成对应的html代码
    private void initViewResolvers(SimpleApplicationContext context) {
    }

    //
    private void initFlashMapManager(SimpleApplicationContext context) {
    }

    private class Handler {

        protected Method method;

        protected Object controller;


        protected Handler(Object controller, Method method) {
            this.controller = controller;
            this.method = method;
        }
    }

    private class HandlerAdapter {
        public void handle(HttpServletRequest req, HttpServletResponse resp, Handler handler) {


        }
    }


    private void out(HttpServletResponse response, String str) {
        try {
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().print(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
